// *************************************************************************************************
//
// MK3D Engine
// --------------------------------------
// Copyright (C) 2007-2011 Zeb (mailto: zebbey@gmail.com)
//
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
// *************************************************************************************************

#include "mk_header.h"
#include "mk_post_processor_manager.h"
#include "mk_post_processor.h"
#include "mk_pp_bloom.h"
#include "mk_pp_twist.h"
#include "mk_render_device.h"
#include "mk_error.h"
#include "mk_engine.h"
#include "mk_texture.h"
#include "mk_render_target.h"
#include "mk_resource_manager.h"
#include "mk_painter.h"
#include "mk_rect.h"
#include "mk_render_window.h"

namespace MK3DE
{
	CPostProcessorManager::CPostProcessorManager()
	{
		_bEnable = FALSE;
		memset(_postProcessorList, 0, sizeof(CPostProcessor*) * PPT_MAX);
		_mainRenderTarget = NULL;
		_swapRenderTarget = NULL;
	}

	CPostProcessorManager::~CPostProcessorManager()
	{
		CRenderDevice* renderDevice = GetEngine()->GetRenderDevice();
		renderDevice->DestroyRenderTarget(_mainRenderTarget);
		renderDevice->DestroyRenderTarget(_swapRenderTarget);
		for (int i = 0; i < (int)PPT_MAX; ++i)
			SAFE_DELETE(_postProcessorList[i]);
	}

	BOOL CPostProcessorManager::Create()
	{
		_postProcessorList[PPT_BLOOM] = new CPostProcessorBloom;
		MK_PROCESS_ERROR(_postProcessorList[PPT_BLOOM]);

		_postProcessorList[PPT_TWIST] = new CPostProcessorTwist;
		MK_PROCESS_ERROR(_postProcessorList[PPT_TWIST]);

		return TRUE;
Exit0:
		return FALSE;
	}

	CPostProcessor* CPostProcessorManager::GetPostProcessor(POST_PROCESS_TYPE type)
	{
		return _postProcessorList[type];
	}

	BOOL CPostProcessorManager::__CreateRenderTarget(CRenderTarget*& renderTarget)
	{
		CEngine* engine = GetEngine();
		CResourceManager* resourceManager = engine->GetResourceManager();
		CRenderDevice* renderDevice = engine->GetRenderDevice();
		CRenderWindow* renderWindow = engine->GetCurrentRenderWindow();
		renderDevice->DestroyRenderTarget(renderTarget);

		DWORD width = renderWindow->GetWidth();
		DWORD height = renderWindow->GetHeight();
		PIXEL_FORMAT format = renderDevice->GetBackBufferFormat();
		BOOL ret = renderDevice->CreateRenderTarget(width, height, format, FALSE, renderTarget);
		MK_PROCESS_ERROR(ret);

		ret = TRUE;
Exit0:
		return ret;
	}

	void CPostProcessorManager::OnDeviceLost()
	{
		CRenderDevice* renderDevice = GetEngine()->GetRenderDevice();
		renderDevice->DestroyRenderTarget(_mainRenderTarget);
		renderDevice->DestroyRenderTarget(_swapRenderTarget);

		for (int i = 0; i < (int)PPT_MAX; ++i)
			_postProcessorList[i]->OnDeviceLost();
	}

	BOOL CPostProcessorManager::BeginFrame()
	{
		if (CPostProcessor::_s_EnabledCount == 0)
			return TRUE;

		if (!_mainRenderTarget)
		{
			if (!__CreateRenderTarget(_mainRenderTarget))
				return FALSE;
		}

		CEngine* engine = GetEngine();
		CRenderDevice* renderDevice = engine->GetRenderDevice();
		CRenderWindow* renderWindow = engine->GetCurrentRenderWindow();
		DWORD width = renderWindow->GetWidth();
		DWORD height = renderWindow->GetHeight();

		BOOL ret = renderDevice->SetRenderTarget(_mainRenderTarget);
		MK_PROCESS_ERROR(ret);

		ret = renderDevice->SetViewport(0, 0, width, height, 0, 1.0f);
		MK_PROCESS_ERROR(ret);

		ret = TRUE;
Exit0:
		return ret;
	}

	BOOL CPostProcessorManager::EndFrame()
	{
		if (CPostProcessor::_s_EnabledCount == 0)
			return TRUE;

		CEngine* engine = GetEngine();
		CRenderDevice* renderDevice = engine->GetRenderDevice();
		CPainter* painter = engine->GetPainter();
		CRenderWindow* renderWindow = engine->GetCurrentRenderWindow();

		// apply all post processor.
		__AppyAllPostProcessor();

		//if (_postProcessorList[PPT_BLOOM]->IsEnable())
		//{
		//	CTexture2D* brightPassTexture = ((CPostProcessorBloom*)_postProcessorList[PPT_BLOOM])->GetBrightPassTexture();
		//	painter->DrawImage2D(Rect2D(0, 0, 128, 128), RectColor(), brightPassTexture);
		//	painter->DrawRect(Rect2D(0, 0, 128, 128), RectColor());
		//	painter->Flush();

		//	CTexture2D* bloomTexture2 = ((CPostProcessorBloom*)_postProcessorList[PPT_BLOOM])->GetBloomTexture(1);
		//	painter->DrawImage2D(Rect2D(128, 0, 256, 128), RectColor(), bloomTexture2);
		//	painter->DrawRect(Rect2D(128, 0, 256, 128), RectColor());
		//	painter->Flush();

		//	CTexture2D* bloomTexture1 = ((CPostProcessorBloom*)_postProcessorList[PPT_BLOOM])->GetBloomTexture(0);
		//	painter->DrawImage2D(Rect2D(256, 0, 384, 128), RectColor(), bloomTexture1);
		//	painter->DrawRect(Rect2D(256, 0, 384, 128), RectColor());
		//	painter->Flush();
		//}

		return TRUE;		
	}

	void CPostProcessorManager::__AppyAllPostProcessor()
	{
		for (int i = 0; i < (int)PPT_MAX; ++i)
		{
			if (_postProcessorList[i]->IsEnable())
			{
				if (CPostProcessor::_s_EnabledCount > 1)
				{
					if (!_mainRenderTarget)
					{
						if (!__CreateRenderTarget(_swapRenderTarget))
							return;
					}
				}

				if (i == CPostProcessor::_s_EnabledCount - 1)
					_postProcessorList[i]->ApplyEffect(_mainRenderTarget, NULL);
				else
					_postProcessorList[i]->ApplyEffect(_mainRenderTarget, _swapRenderTarget);

				if (CPostProcessor::_s_EnabledCount > 1)
				{
					CRenderTarget* t = _mainRenderTarget;
					_mainRenderTarget = _swapRenderTarget;
					_swapRenderTarget = t;
				}
			}
		}
	}
}